package org.huangrui.juc.source.atomic;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAccumulator;
import java.util.concurrent.atomic.LongAdder;

/**
 * 需求： 50个线程，每个线程100W次，总点赞数出来
 *
 * @Author hr
 * @Create 2024-04-12 06:14
 */
public class T07_AccumulatorCompare {
    public static final int _1W = 10000;
    public static final int THREADNUMBER = 50;


    public static void main(String[] args) throws InterruptedException {
        long startTime, endTime;
        ClickNumber clickNumber = new ClickNumber();
        CountDownLatch downLatch = new CountDownLatch(50);
        CountDownLatch downLatch1 = new CountDownLatch(50);
        CountDownLatch downLatch2 = new CountDownLatch(50);
        CountDownLatch downLatch3 = new CountDownLatch(50);

        startTime = System.currentTimeMillis();
        for (int i = 1; i <= THREADNUMBER; i++) {
            new Thread(() -> {
                try {
                    for (int j = 1; j <= 100 * _1W; j++) {
                        clickNumber.clickBySynchronized();
                    }
                } finally {
                    downLatch.countDown();
                }
            }, String.valueOf(i)).start();
        }
        downLatch.await();
        endTime = System.currentTimeMillis();
        System.out.println("----costTime:" + (endTime - startTime) + "毫秒\t clickBySynchronized: " + clickNumber.number);

        startTime = System.currentTimeMillis();
        for (int i = 1; i <= THREADNUMBER; i++) {
            new Thread(() -> {
                try {
                    for (int j = 0; j < 100 * _1W; j++) {
                        clickNumber.clickByAtomicLong();
                    }
                } finally {
                    downLatch1.countDown();
                }
            }, String.valueOf(i)).start();
        }
        downLatch1.await();
        endTime = System.currentTimeMillis();
        System.out.println("----costTime:" + (endTime - startTime) + "毫秒\t clickByAtomicLong: " + clickNumber.atomicLong.get());

        startTime = System.currentTimeMillis();
        for (int i = 1; i <= THREADNUMBER; i++) {
            new Thread(() -> {
                try {
                    for (int j = 1; j <= 100 * _1W; j++) {
                        clickNumber.clickByLongAdder();
                    }
                } finally {
                    downLatch2.countDown();
                }
            }, String.valueOf(i)).start();
        }
        downLatch2.await();
        endTime = System.currentTimeMillis();
        System.out.println("----costTime:" + (endTime - startTime) + "毫秒\t clickByLongAdder: " + clickNumber.longAdder.sum());

        startTime = System.currentTimeMillis();
        for (int i = 1; i <= THREADNUMBER; i++) {
            new Thread(() -> {
                try {
                    for (int j = 1; j <= 100 * _1W; j++) {
                        clickNumber.clickByLongAccumulator();
                    }
                } finally {
                    downLatch3.countDown();
                }
            }, String.valueOf(i)).start();
        }
        downLatch3.await();
        endTime = System.currentTimeMillis();
        System.out.println("----costTime:" + (endTime - startTime) + "毫秒\t clickByLongAccumulator: " + clickNumber.longAccumulator.get());
    }
}

class ClickNumber {
    int number = 0;

    public synchronized void clickBySynchronized() {
        number++;
    }

    AtomicLong atomicLong = new AtomicLong(0);

    public void clickByAtomicLong() {
        atomicLong.getAndIncrement();
    }

    LongAdder longAdder = new LongAdder();

    public void clickByLongAdder() {
        longAdder.increment();
    }

    LongAccumulator longAccumulator = new LongAccumulator(Long::sum, 0);


    public void clickByLongAccumulator() {
        longAccumulator.accumulate(1);
    }

}